package com.czk.future;

import com.czk.msg.Request;
import com.czk.msg.Response;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;

import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/4/27 10:43
 */
public class SyncWrite {
    /**
     * 同步写
     *
     * @param channel
     * @param request
     * @param timeout
     * @return
     * @throws Exception
     */
    public Response writeAndSync(final Channel channel, final Request request, final long timeout) throws Exception {
        // 校验参数
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        if (request == null) {
            throw new NullPointerException("request");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout<0");
        }
        // 拿到随机id
        String id = UUID.randomUUID().toString().replaceAll("-", "");
        // 设置
        request.setRequestId(id);
        SyncWriteFuture future = new SyncWriteFuture(request.getRequestId());
        // 存入缓存
        SyncWriteMap.syncKey.put(request.getRequestId(), future);
        // 这里会阻塞，写然后拿到返回结果
        Response response = doWriteAndSync(channel, request, timeout, future);
        // 返回结果
        return response;
    }

    /**
     * 同步写
     *
     * @param channel
     * @param request
     * @param timeout
     * @param future
     * @return
     * @throws Exception
     */
    private Response doWriteAndSync(Channel channel, Request request, long timeout, SyncWriteFuture future) throws Exception {
        channel.writeAndFlush(request).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                // 设置是否成功
                future.setWriteResult(channelFuture.isSuccess());
                // 设置错误信息
                future.setCause(channelFuture.cause());
                // 失败移除
                if (!channelFuture.isSuccess()) {
                    SyncWriteMap.syncKey.remove(request.getRequestId());
                }
            }
        });
        System.out.println("释放前");
        // 拿到结果
        Response response = future.get(timeout, TimeUnit.SECONDS);
        System.out.println("释放了");
        if (response == null) {
            // 是否超时
            if (future.isTimeout()) {
                throw new TimeoutException();
            } else {
                throw new Exception(future.cause());
            }
        }
        return response;
    }
}
